// 区域和检索 - 数组可修改

package Leetcode;

class NumArray {
    // 每个结点存储[s,e]的总和
    // root存储nums[0,n-1]的总和
    // root.left存储nums[0,(n-1)/2]的总和，以此类推
    // 最终left=nums[k]
    private int[] segmentTree;
    private int n;

    public NumArray(int[] nums) {
        n = nums.length;
        segmentTree = new int[nums.length * 4];
        build(0, 0, n - 1, nums);
    }

    public void update(int index, int val) {
        change(index, val, 0, 0, n - 1);
    }

    public int sumRange(int left, int right) {
        return range(left, right, 0, 0, n - 1);
    }

    // (根节点，左边界，右边界，数组)
    // 自下而上先赋值叶子结点，最后赋值根结点
    private void build(int node, int s, int e, int[] nums) {
        // s=e表示叶子
        if (s == e) {
            segmentTree[node] = nums[s];
            return;
        }
        int m = s + (e - s) / 2;
        build(node * 2 + 1, s, m, nums);
        build(node * 2 + 2, m + 1, e, nums);
        segmentTree[node] = segmentTree[node * 2 + 1] + segmentTree[node * 2 + 2];
    }

    // 时间复杂度：O(logN)
    private void change(int index, int val, int node, int s, int e) {
        // 找到index，进行更新
        if (s == e) {
            segmentTree[node] = val;
            return;
        }
        int m = s + (e - s) / 2;
        // 判断index处于左子树还是右子树
        if (index <= m) {
            change(index, val, node * 2 + 1, s, m);
        } else {
            change(index, val, node * 2 + 2, m + 1, e);
        }
        // 自下而上更新值
        segmentTree[node] = segmentTree[node * 2 + 1] + segmentTree[node * 2 + 2];
    }

    private int range(int left, int right, int node, int s, int e) {
        // 找到范围直接返回
        if (left == s && right == e) {
            return segmentTree[node];
        }
        int m = s + (e - s) / 2;
        if (right <= m) {
            return range(left, right, node * 2 + 1, s, m);
        } else if (left > m) {
            return range(left, right, node * 2 + 2, m + 1, e);
        } else {
            // m处于left和right之间，需要分段求和
            return range(left, m, node * 2 + 1, s, m) + range(m + 1, right, node * 2 + 2, m + 1, e);
        }
    }
}
